#include "sema.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Casting.h"

// 符号声明节点
std::shared_ptr<ASTNode> Sema::SemaVariableDeclNode(llvm::StringRef name, CType *ty)
{
    auto symbol = scope.FindVarSymbolInCurEnv(name);
    if (symbol) // 查找是否重定义
    {
        llvm::errs() << "redefine name: " << name << "\n";
        return nullptr;
    }

    scope.AddVarSymbol(SymbolKind::LocalVariable, ty, name); // 添加到符号表

    auto variableDecl = std::make_shared<VariableDecl>();
    variableDecl->name = name;
    variableDecl->type = ty;

    return variableDecl;
}

std::shared_ptr<ASTNode> Sema::SemaVariableAccessNode(llvm::StringRef name)
{
    auto symbol = scope.FindVarSymbol(name);
    // auto symbol = scope.FindVarSymbolInCurEnv(name); // err
    if (symbol == nullptr)
    {
        llvm::errs() << "can't use no define variable name: " << name << "\n";
        return nullptr;
    }
    auto varAcc = std::make_shared<VariableAccessExpr>();
    varAcc->name = name;
    varAcc->type = symbol->getTy();
    return varAcc;
}

std::shared_ptr<ASTNode> Sema::SemaAssignExprNode(std::shared_ptr<ASTNode> left, std::shared_ptr<ASTNode> right)
{
    if (!left || !right)
    {
        llvm::errs() << "left or right can't be nullptr!\n";
        return nullptr;
    }

    if (!llvm::isa<VariableAccessExpr>(left.get()))
    {
        llvm::errs() << "left must be left value!\n";
        return nullptr;
    }

    auto assign = std::make_shared<AssignExpr>();
    assign->left = left;
    assign->right = right;

    return assign;
}

std::shared_ptr<ASTNode> Sema::SemaBinaryExprNode(std::shared_ptr<ASTNode> left, std::shared_ptr<ASTNode> right, OpCode op)
{
    auto binaryExpr = std::make_shared<BinaryExpr>();
    binaryExpr->left = left;
    binaryExpr->right = right;
    binaryExpr->op = op;

    return binaryExpr;
}

std::shared_ptr<ASTNode> Sema::SemaNumberExprNode(int value, CType* ty)
{
    auto factorExpr = std::make_shared<NumberExpr>();
    factorExpr->number = value;
    factorExpr->type = ty;

    return factorExpr;
}